home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / cc / g++-dist / cplus-dem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-17  |  17.9 KB  |  961 lines

  1. /* Demangler for GNU C++ 
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.    written by James Clark (jjc@jclark.uucp)
  4.    
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 1, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. /* This is for g++ 1.36.1 (November 6 version). It will probably
  20.    require changes for any other version.
  21.  
  22.    Modified for g++ 1.36.2 (November 18 version).  */
  23.  
  24. /* This file exports one function
  25.  
  26.    char *cplus_demangle (const char *name)
  27.    
  28.    If `name' is a mangled function name produced by g++, then
  29.    a pointer to a malloced string giving a C++ representation
  30.    of the name will be returned; otherwise NULL will be returned.
  31.    It is the caller's responsibility to free the string which
  32.    is returned.
  33.  
  34.    For example,
  35.    
  36.    cplus_demangle ("_foo__1Ai")
  37.    
  38.    returns
  39.  
  40.    "A::foo(int)"
  41.  
  42.    This file imports xmalloc and xrealloc, which are like malloc and
  43.    realloc except that they generate a fatal error if there is no
  44.    available memory. */
  45.  
  46. /* #define nounderscore 1 /* define this is names don't start with _ */
  47.  
  48. #include <stdio.h>
  49. #include <string.h>
  50. #include <ctype.h>
  51.  
  52. #ifdef USG
  53. #include <memory.h>
  54. #else
  55. #define memcpy(s1, s2, n) bcopy ((s2), (s1), (n)) 
  56. #define memcmp(s1, s2, n) bcmp ((s2), (s1), (n))
  57. #define strchr index 
  58. #define strrchr rindex
  59. #endif
  60.  
  61. #ifndef __STDC__
  62. #define const
  63. #endif
  64.  
  65. #ifdef __STDC__
  66. extern char *cplus_demangle (const char *type);
  67. #else
  68. extern char *cplus_demangle ();
  69. #endif
  70.  
  71. #ifdef __STDC__
  72. extern char *xmalloc (int);
  73. extern char *xrealloc (char *, int);
  74. #else
  75. extern char *xmalloc ();
  76. extern char *xrealloc ();
  77. #endif
  78.  
  79. static char **typevec = 0;
  80. static int ntypes = 0;
  81. static int typevec_size = 0;
  82.  
  83. static struct {
  84.   const char *in;
  85.   const char *out;
  86. } optable[] = {
  87.   "new", " new",
  88.   "delete", " delete",
  89.   "ne", "!=",
  90.   "eq", "==",
  91.   "ge", ">=",
  92.   "gt", ">",
  93.   "le", "<=",
  94.   "lt", "<",
  95.   "plus", "+",
  96.   "minus", "-",
  97.   "mult", "*",
  98.   "convert", "+",    /* unary + */
  99.   "negate", "-",    /* unary - */
  100.   "trunc_mod", "%",
  101.   "trunc_div", "/",
  102.   "truth_andif", "&&",
  103.   "truth_orif", "||",
  104.   "truth_not", "!",
  105.   "postincrement", "++",
  106.   "postdecrement", "--",
  107.   "bit_ior", "|",
  108.   "bit_xor", "^",
  109.   "bit_and", "&",
  110.   "bit_not", "~",
  111.   "call", "()",
  112.   "cond", "?:",
  113.   "alshift", "<<",
  114.   "arshift", ">>",
  115.   "component", "->",
  116.   "indirect", "*",
  117.   "method_call", "->()",
  118.   "addr", "&",        /* unary & */
  119.   "array", "[]",
  120.   "nop", "",            /* for operator= */
  121. };
  122.  
  123. /* Beware: these aren't '\0' terminated. */
  124.  
  125. typedef struct {
  126.   char *b;            /* pointer to start of string */
  127.   char *p;            /* pointer after last character */
  128.   char *e;            /* pointer after end of allocated space */
  129. } string;
  130.  
  131. #ifdef __STDC__
  132. static void string_need (string *s, int n);
  133. static void string_delete (string *s);
  134. static void string_init (string *s);
  135. static void string_clear (string *s);
  136. static int string_empty (string *s);
  137. static void string_append (string *p, const char *s);
  138. static void string_appends (string *p, string *s);
  139. static void string_appendn (string *p, const char *s, int n);
  140. static void string_prepend (string *p, const char *s);
  141. #if 0
  142. static void string_prepends (string *p, string *s);
  143. #endif
  144. static void string_prependn (string *p, const char *s, int n);
  145. static int get_count (const char **type, int *count);
  146. static int do_args (const char **type, string *decl);
  147. static int do_type (const char **type, string *result);
  148. static int do_arg (const char **type, string *result);
  149. static int do_args (const char **type, string *decl);
  150. static void munge_function_name (string *name);
  151. #else
  152. static void string_need ();
  153. static void string_delete ();
  154. static void string_init ();
  155. static void string_clear ();
  156. static int string_empty ();
  157. static void string_append ();
  158. static void string_appends ();
  159. static void string_appendn ();
  160. static void string_prepend ();
  161. static void string_prepends ();
  162. static void string_prependn ();
  163. static int get_count ();
  164. static int do_args ();
  165. static int do_type ();
  166. static int do_arg ();
  167. static int do_args ();
  168. static void munge_function_name ();
  169. #endif
  170.  
  171. char *
  172. cplus_demangle (type)
  173.      const char *type;
  174. {
  175.   string decl;
  176.   int n;
  177.   int success = 0;
  178.   int constructor = 0;
  179.   int const_flag = 0;
  180.   int i;
  181.   const char *p, *premangle;
  182.  
  183.   if (type == NULL || *type == '\0')
  184.     return NULL;
  185. #ifndef nounderscore
  186.   if (*type++ != '_')
  187.     return NULL;
  188. #endif
  189.   p = type;
  190.   while (*p != '\0' && !(*p == '_' && p[1] == '_'))
  191.     p++;
  192.   if (*p == '\0')
  193.     {
  194.       /* destructor */
  195.       if (type[0] == '_' && type[1] == '$' && type[2] == '_')
  196.     {
  197.       int n = (strlen (type) - 3)*2 + 3 + 2 + 1;
  198.       char *tem = (char *) xmalloc (n);
  199.       strcpy (tem, type + 3);
  200.       strcat (tem, "::~");
  201.       strcat (tem, type + 3);
  202.       strcat (tem, "()");
  203.       return tem;
  204.     }
  205.       /* static data member */
  206.       if (*type != '_' && (p = strchr (type, '$')) != NULL)
  207.     {
  208.       int n = strlen (type) + 2;
  209.       char *tem = (char *) xmalloc (n);
  210.       memcpy (tem, type, p - type);
  211.       strcpy (tem + (p - type), "::");
  212.       strcpy (tem + (p - type) + 2, p + 1);
  213.       return tem;
  214.     }
  215.       /* virtual table */
  216.       if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$')
  217.     {
  218.       int n = strlen (type + 4) + 14 + 1;
  219.       char *tem = (char *) xmalloc (n);
  220.       strcpy (tem, type + 4);
  221.       strcat (tem, " virtual table");
  222.       return tem;
  223.     }
  224.       return NULL;
  225.     }
  226.  
  227.   string_init (&decl);
  228.  
  229.   if (p == type)
  230.     {
  231.       if (!isdigit (p[2]))
  232.     {
  233.       string_delete (&decl);
  234.       return NULL;
  235.     }
  236.       constructor = 1;
  237.     }
  238.   else
  239.     {
  240.       string_appendn (&decl, type, p - type);
  241.       munge_function_name (&decl);
  242.     }
  243.   p += 2;
  244.  
  245.   premangle = p;
  246.   switch (*p)
  247.     {
  248.     case 'C':
  249.       /* a const member function */
  250.       if (!isdigit (p[1]))
  251.     {
  252.       string_delete (&decl);
  253.       return NULL;
  254.     }
  255.       p += 1;
  256.       const_flag = 1;
  257.       /* fall through */
  258.     case '0':
  259.     case '1':
  260.     case '2':
  261.     case '3':
  262.     case '4':
  263.     case '5':
  264.     case '6':
  265.     case '7':
  266.     case '8':
  267.     case '9':
  268.       n = 0;
  269.       do
  270.     {
  271.       n *= 10;
  272.       n += *p - '0';
  273.       p += 1;
  274.     }
  275.       while (isdigit (*p));
  276.       if (strlen (p) < n)
  277.     {
  278.       string_delete (&decl);
  279.       return NULL;
  280.     }
  281.       if (constructor)
  282.     {
  283.       string_appendn (&decl, p, n);
  284.       string_append (&decl, "::");
  285.       string_appendn (&decl, p, n);
  286.     }
  287.       else
  288.     {
  289.       string_prepend (&decl, "::");
  290.       string_prependn (&decl, p, n);
  291.     }
  292. #ifndef LONGERNAMES
  293.       p = premangle;
  294. #else
  295.       p += n;
  296. #endif
  297.       success = do_args (&p, &decl);
  298.       if (const_flag)
  299.     string_append (&decl, " const");
  300.       break;
  301.     case 'F':
  302.       p += 1;
  303.       success = do_args (&p, &decl);
  304.       break;
  305.     }
  306.  
  307.   for (i = 0; i < ntypes; i++)
  308.     if (typevec[i] != NULL)
  309.       free (typevec[i]);
  310.   ntypes = 0;
  311.   if (typevec != NULL)
  312.     {
  313.       free ((char *)typevec);
  314.       typevec = NULL;
  315.       typevec_size = 0;
  316.     }
  317.  
  318.   if (success)
  319.     {
  320.       string_appendn (&decl, "", 1);
  321.       return decl.b;
  322.     }
  323.   else
  324.     {
  325.       string_delete (&decl);
  326.       return NULL;
  327.     }
  328. }
  329.  
  330. static int
  331. get_count (type, count)
  332.      const char **type;
  333.      int *count;
  334. {
  335.   if (!isdigit (**type))
  336.     return 0;
  337.   *count = **type - '0';
  338.   *type += 1;
  339.   /* see flush_repeats in cplus-method.c */
  340.   if (isdigit (**type))
  341.     {
  342.       const char *p = *type;
  343.       int n = *count;
  344.       do 
  345.     {
  346.       n *= 10;
  347.       n += *p - '0';
  348.       p += 1;
  349.     } 
  350.       while (isdigit (*p));
  351.       if (*p == '_')
  352.     {
  353.       *type = p + 1;
  354.       *count = n;
  355.     }
  356.     }
  357.   return 1;
  358. }
  359.  
  360. /* result will be initialised here; it will be freed on failure */
  361.  
  362. static int
  363. do_type (type, result)
  364.      const char **type;
  365.      string *result;
  366. {
  367.   int n;
  368.   int done;
  369.   int non_empty = 0;
  370.   int success;
  371.   string decl;
  372.   const char *remembered_type;
  373.  
  374.   string_init (&decl);
  375.   string_init (result);
  376.  
  377.   done = 0;
  378.   success = 1;
  379.   while (success && !done)
  380.     {
  381.       int member;
  382.       switch (**type)
  383.     {
  384.     case 'P':
  385.       *type += 1;
  386.       string_prepend (&decl, "*");
  387.       break;
  388.  
  389.     case 'R':
  390.       *type += 1;
  391.       string_prepend (&decl, "&");
  392.       break;
  393.  
  394.     case 'T':
  395.       *type += 1;
  396.       if (!get_count (type, &n) || n >= ntypes)
  397.         success = 0;
  398.       else
  399.         {
  400.           remembered_type = typevec[n];
  401.           type = &remembered_type;
  402.         }
  403.       break;
  404.  
  405.     case 'F':
  406.       *type += 1;
  407.       if (!string_empty (&decl) && decl.b[0] == '*')
  408.         {
  409.           string_prepend (&decl, "(");
  410.           string_append (&decl, ")");
  411.         }
  412.       if (!do_args (type, &decl) || **type != '_')
  413.         success = 0;
  414.       else
  415.         *type += 1;
  416.       break;
  417.  
  418.     case 'M':
  419.     case 'O':
  420.       {
  421.         int constp = 0;
  422.         int volatilep = 0;
  423.  
  424.         member = **type == 'M';
  425.         *type += 1;
  426.         if (!isdigit (**type))
  427.           {
  428.         success = 0;
  429.         break;
  430.           }
  431.         n = 0;
  432.         do
  433.           {
  434.         n *= 10;
  435.         n += **type - '0';
  436.         *type += 1;
  437.           } 
  438.         while (isdigit (**type));
  439.         if (strlen (*type) < n)
  440.           {
  441.         success = 0;
  442.         break;
  443.           }
  444.         string_append (&decl, ")");
  445.         string_prepend (&decl, "::");
  446.         string_prependn (&decl, *type, n);
  447.         string_prepend (&decl, "(");
  448.         *type += n;
  449.         if (member)
  450.           {
  451.         if (**type == 'C')
  452.           {
  453.             *type += 1;
  454.             constp = 1;
  455.           }
  456.         if (**type == 'V')
  457.           {
  458.             *type += 1;
  459.             volatilep = 1;
  460.           }
  461.         if (*(*type)++ != 'F')
  462.           {
  463.             success = 0;
  464.             break;
  465.           }
  466.           }
  467.         if ((member && !do_args (type, &decl)) || **type != '_')
  468.           {
  469.         success = 0;
  470.         break;
  471.           }
  472.         *type += 1;
  473.         if (constp)
  474.           {
  475.         if (non_empty)
  476.           string_append (&decl, " ");
  477.         else
  478.           non_empty = 1;
  479.         string_append (&decl, "const");
  480.           }
  481.         if (volatilep)
  482.           {
  483.         if (non_empty)
  484.           string_append (&decl, " ");
  485.         else
  486.           non_empty = 1;
  487.         string_append (&decl, "volatilep");
  488.           }
  489.         break;
  490.       }
  491.  
  492.     case 'C':
  493.       if ((*type)[1] == 'P')
  494.         {
  495.           *type += 1;
  496.           if (!string_empty (&decl))
  497.         string_prepend (&decl, " ");
  498.           string_prepend (&decl, "const");
  499.           break;
  500.         }
  501.  
  502.       /* fall through */
  503.     default:
  504.       done = 1;
  505.       break;
  506.     }
  507.     }
  508.  
  509.   done = 0;
  510.   non_empty = 0;
  511.   while (success && !done)
  512.     {
  513.       switch (**type)
  514.     {
  515.     case 'C':
  516.       *type += 1;
  517.       if (non_empty)
  518.         string_append (result, " ");
  519.       else
  520.         non_empty = 1;
  521.       string_append (result, "const");
  522.       break;
  523.     case 'U':
  524.       *type += 1;
  525.       if (non_empty)
  526.         string_append (result, " ");
  527.       else
  528.         non_empty = 1;
  529.       string_append (result, "unsigned");
  530.       break;
  531.     case 'V':
  532.       *type += 1;
  533.       if (non_empty)
  534.         string_append (result, " ");
  535.       else
  536.         non_empty = 1;
  537.       string_append (result, "volatile");
  538.       break;
  539.     default:
  540.       done = 1;
  541.       break;
  542.     }
  543.     }
  544.  
  545.   if (success)
  546.     switch (**type)
  547.       {
  548.       case '\0':
  549.       case '_':
  550.     break;
  551.       case 'v':
  552.     *type += 1;
  553.     if (non_empty)
  554.       string_append (result, " ");
  555.     string_append (result, "void");
  556.     break;
  557.       case 'l':
  558.     *type += 1;
  559.     if (non_empty)
  560.       string_append (result, " ");
  561.     string_append (result, "long");
  562.     break;
  563.       case 'i':
  564.     *type += 1;
  565.     if (non_empty)
  566.       string_append (result, " ");
  567.     string_append (result, "int");
  568.     break;
  569.       case 's':
  570.     *type += 1;
  571.     if (non_empty)
  572.       string_append (result, " ");
  573.     string_append (result, "short");
  574.     break;
  575.       case 'c':
  576.     *type += 1;
  577.     if (non_empty)
  578.       string_append (result, " ");
  579.     string_append (result, "char");
  580.     break;
  581.       case 'r':
  582.     *type += 1;
  583.     if (non_empty)
  584.       string_append (result, " ");
  585.     string_append (result, "long double");
  586.     break;
  587.       case 'd':
  588.     *type += 1;
  589.     if (non_empty)
  590.       string_append (result, " ");
  591.     string_append (result, "double");
  592.     break;
  593.       case 'f':
  594.     *type += 1;
  595.     if (non_empty)
  596.       string_append (result, " ");
  597.     string_append (result, "float");
  598.     break;
  599.       case 'G':
  600.     *type += 1;
  601.     if (!isdigit (**type))
  602.       {
  603.         success = 0;
  604.         break;
  605.       }
  606.     /* fall through */
  607.       case '0':
  608.       case '1':
  609.       case '2':
  610.       case '3':
  611.       case '4':
  612.       case '5':
  613.       case '6':
  614.       case '7':
  615.       case '8':
  616.       case '9':
  617.     n = 0;
  618.     do
  619.       {
  620.         n *= 10;
  621.         n += **type - '0';
  622.         *type += 1;
  623.       }
  624.     while (isdigit (**type));
  625.     if (strlen (*type) < n)
  626.       {
  627.         success = 0;
  628.         break;
  629.       }
  630.     if (non_empty)
  631.       string_append (result, " ");
  632.     string_appendn (result, *type, n);
  633.     *type += n;
  634.     break;
  635.       default:
  636.     success = 0;
  637.     break;
  638.       }
  639.  
  640.   if (success)
  641.     {
  642.       if (!string_empty (&decl))
  643.     {
  644.       string_append (result, " ");
  645.       string_appends (result, &decl);
  646.     }
  647.       string_delete (&decl);
  648.       return 1;
  649.     }
  650.   else
  651.     {
  652.       string_delete (&decl);
  653.       string_delete (result);
  654.       return 0;
  655.     }
  656. }
  657.  
  658. /* `result' will be initialised in do_type; it will be freed on failure */
  659.  
  660. static int
  661. do_arg (type, result)
  662.      const char **type;
  663.      string *result;
  664. {
  665.   char *tem;
  666.   int len;
  667.   const char *start;
  668.   const char *end;
  669.  
  670.   start = *type;
  671.   if (!do_type (type, result))
  672.     return 0;
  673.   end = *type;
  674.   if (ntypes >= typevec_size)
  675.     {
  676.       if (typevec_size == 0)
  677.     {
  678.       typevec_size = 3;
  679.       typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
  680.     }
  681.       else
  682.     {
  683.       typevec_size *= 2;
  684.       typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
  685.     }
  686.     }
  687.   len = end - start;
  688.   tem = (char *) xmalloc (len + 1);
  689.   memcpy (tem, start, len);
  690.   tem[len] = '\0';
  691.   typevec[ntypes++] = tem;
  692.   return 1;
  693. }
  694.  
  695. /* `decl' must be already initialised, usually non-empty;
  696.    it won't be freed on failure */
  697.  
  698. static int
  699. do_args (type, decl)
  700.      const char **type;
  701.      string *decl;
  702. {
  703.   string arg;
  704.   int need_comma = 0;
  705.   int dont_want_first;
  706.  
  707. #ifndef LONGERNAMES
  708.   dont_want_first = 1;
  709. #else
  710.   dont_want_first = 0;
  711. #endif
  712.  
  713.   string_append (decl, "(");
  714.  
  715.   while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
  716.     {
  717.       if (**type == 'N')
  718.     {
  719.       int r;
  720.       int t;
  721.       *type += 1;
  722.       if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
  723.         return 0;
  724.       while (--r >= 0)
  725.         {
  726.           const char *tem = typevec[t];
  727.           if (need_comma)
  728.         string_append (decl, ", ");
  729.           if (!do_arg (&tem, &arg))
  730.         return 0;
  731.           string_appends (decl, &arg);
  732.           string_delete (&arg);
  733.           need_comma = 1;
  734.         }
  735.     }
  736.       else
  737.     {
  738.       if (need_comma)
  739.         string_append (decl, ", ");
  740.       if (!do_arg (type, &arg))
  741.         return 0;
  742.       if (dont_want_first)
  743.         dont_want_first = 0;
  744.       else
  745.         {
  746.           string_appends (decl, &arg);
  747.           need_comma = 1;
  748.         }
  749.       string_delete (&arg);
  750.     }
  751.     }
  752.  
  753.   if (**type == 'v')
  754.     *type += 1;
  755.   else if (**type == 'e')
  756.     {
  757.       *type += 1;
  758.       if (need_comma)
  759.     string_append (decl, ",");
  760.       string_append (decl, "...");
  761.     }
  762.  
  763.   string_append (decl, ")");
  764.   return 1;
  765. }
  766.  
  767. static void
  768. munge_function_name (name)
  769.      string *name;
  770. {
  771.   if (!string_empty (name) && name->p - name->b >= 3 
  772.       && name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
  773.     {
  774.       int i;
  775.       /* see if it's an assignment expression */
  776.       if (name->p - name->b >= 10 /* op$assign_ */
  777.       && memcmp (name->b + 3, "assign_", 7) == 0)
  778.     {
  779.       for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
  780.         {
  781.           int len = name->p - name->b - 10;
  782.           if (strlen (optable[i].in) == len
  783.           && memcmp (optable[i].in, name->b + 10, len) == 0)
  784.         {
  785.           string_clear (name);
  786.           string_append (name, "operator");
  787.           string_append (name, optable[i].out);
  788.           string_append (name, "=");
  789.           return;
  790.         }
  791.         }
  792.     }
  793.       else
  794.     {
  795.       for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
  796.         {
  797.           int len = name->p - name->b - 3;
  798.           if (strlen (optable[i].in) == len 
  799.           && memcmp (optable[i].in, name->b + 3, len) == 0)
  800.         {
  801.           string_clear (name);
  802.           string_append (name, "operator");
  803.           string_append (name, optable[i].out);
  804.           return;
  805.         }
  806.         }
  807.     }
  808.       return;
  809.     }
  810.   else if (!string_empty (name) && name->p - name->b >= 5
  811.        && memcmp (name->b, "type$", 5) == 0)
  812.     {
  813.       /* type conversion operator */
  814.       string type;
  815.       const char *tem = name->b + 5;
  816.       if (do_type (&tem, &type))
  817.     {
  818.       string_clear (name);
  819.       string_append (name, "operator ");
  820.       string_appends (name, &type);
  821.       string_delete (&type);
  822.       return;
  823.     }
  824.     }
  825. }
  826.  
  827. /* a mini string-handling package */
  828.  
  829. static void
  830. string_need (s, n)
  831.      string *s;
  832.      int n;
  833. {
  834.   if (s->b == NULL)
  835.     {
  836.       if (n < 32)
  837.     n = 32;
  838.       s->p = s->b = (char *) xmalloc (n);
  839.       s->e = s->b + n;
  840.     }
  841.   else if (s->e - s->p < n)
  842.     {
  843.       int tem = s->p - s->b;
  844.       n += tem;
  845.       n *= 2;
  846.       s->b = (char *) xrealloc (s->b, n);
  847.       s->p = s->b + tem;
  848.       s->e = s->b + n;
  849.     }
  850. }
  851.  
  852. static void
  853. string_delete (s)
  854.      string *s;
  855. {
  856.   if (s->b != NULL)
  857.     {
  858.       free (s->b);
  859.       s->b = s->e = s->p = NULL;
  860.     }
  861. }
  862.  
  863. static void
  864. string_init (s)
  865.      string *s;
  866. {
  867.   s->b = s->p = s->e = NULL;
  868. }
  869.  
  870. static void 
  871. string_clear (s)
  872.      string *s;
  873. {
  874.   s->p = s->b;
  875. }
  876.  
  877. static int
  878. string_empty (s)
  879.      string *s;
  880. {
  881.   return s->b == s->p;
  882. }
  883.  
  884. static void
  885. string_append (p, s)
  886.      string *p;
  887.      const char *s;
  888. {
  889.   int n;
  890.   if (s == NULL || *s == '\0')
  891.     return;
  892.   n = strlen (s);
  893.   string_need (p, n);
  894.   memcpy (p->p, s, n);
  895.   p->p += n;
  896. }
  897.  
  898. static void
  899. string_appends (p, s)
  900.      string *p, *s;
  901. {
  902.   int n;
  903.   if (s->b == s->p)
  904.     return;
  905.   n = s->p - s->b;
  906.   string_need (p, n);
  907.   memcpy (p->p, s->b, n);
  908.   p->p += n;
  909. }
  910.  
  911. static void
  912. string_appendn (p, s, n)
  913.      string *p;
  914.      const char *s;
  915.      int n;
  916. {
  917.   if (n == 0)
  918.     return;
  919.   string_need (p, n);
  920.   memcpy (p->p, s, n);
  921.   p->p += n;
  922. }
  923.  
  924. static void
  925. string_prepend (p, s)
  926.      string *p;
  927.      const char *s;
  928. {
  929.   if (s == NULL || *s == '\0')
  930.     return;
  931.   string_prependn (p, s, strlen (s));
  932. }
  933.  
  934. #if 0
  935. static void
  936. string_prepends (p, s)
  937.      string *p, *s;
  938. {
  939.   if (s->b == s->p)
  940.     return;
  941.   string_prependn (p, s->b, s->p - s->b);
  942. }
  943. #endif
  944.  
  945. static void
  946. string_prependn (p, s, n)
  947.      string *p;
  948.      const char *s;
  949.      int n;
  950. {
  951.   char *q;
  952.  
  953.   if (n == 0)
  954.     return;
  955.   string_need (p, n);
  956.   for (q = p->p - 1; q >= p->b; q--)
  957.     q[n] = q[0];
  958.   memcpy (p->b, s, n);
  959.   p->p += n;
  960. }
  961.